package com.lcf.framework.utils.oss;

import cn.hutool.core.collection.CollectionUtil;
import com.lcf.framework.config.oss.OssConfig;
import com.lcf.framework.exception.SysException;
import com.lcf.framework.utils.oss.ali.AliOssUtils;
import com.lcf.framework.utils.oss.minio.MinioOssUtils;
import com.lcf.system.enums.OssTypeEnum;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.util.*;

/**
 * oss
 *
 * @author lcf
 */
@Component
public class OssUtils {
    @Resource
    private OssConfig ossConfig;
    private static IOssUtils ossUtils;
    @Resource
    private AliOssUtils aliOssUtils;
    @Resource
    private MinioOssUtils minioOssUtils;

    /**
     * 初始化静态成员
     */
    @PostConstruct
    private void init() {
        OssConfig ossConfig = this.ossConfig;
        if (Objects.equals(ossConfig.getType(), OssTypeEnum.ALI.getName())) {
            ossUtils = this.aliOssUtils;
        }

        if (Objects.equals(ossConfig.getType(), OssTypeEnum.MINIO.getName())) {
            ossUtils = this.minioOssUtils;
        }
    }

    /**
     * 上传图片
     *
     * @param file       文件
     * @param path       相对路径
     * @param isCompress 是否压缩
     */
    public static String uploadImg(String path, MultipartFile file, boolean isCompress) {
        checkImg(file.getOriginalFilename());
        return ossUtils.uploadImg(path, file, isCompress);
    }

    /**
     * 上传图片
     *
     * @param path       相对路径
     * @param isCompress 是否压缩
     */
    public static String uploadImg(String path, InputStream inputStream, boolean isCompress) {
        return ossUtils.uploadImg(path, inputStream, isCompress);
    }

    /**
     * 上传图片
     *
     * @param url        文件url
     * @param path       相对路径
     * @param isCompress 是否压缩
     */
    public static String uploadImg(String path, String url, boolean isCompress) {
        checkImg(url);
        return ossUtils.uploadImg(path, url, isCompress);
    }

    /**
     * 更新图片
     *
     * @param inputStream 图片流
     * @param oldName     旧图片名
     */
    public static String updateImg(String bucket, InputStream inputStream, String oldName, boolean isCompress) {
        return ossUtils.updateImg(bucket, inputStream, oldName, isCompress);
    }

    /**
     * 更新图片
     *
     * @param file    图片
     * @param oldName 旧图片名
     */
    public static String updateImg(String bucket, MultipartFile file, String oldName, boolean isCompress) {
        return ossUtils.updateImg(bucket, file, oldName, isCompress);
    }

    /**
     * 更新图片
     *
     * @param fileUrl 新图片路径
     * @param oldName 旧图片名
     */
    public static String updateImg(String bucket, String fileUrl, String oldName, boolean isCompress) {
        return ossUtils.updateImg(bucket, fileUrl, oldName, isCompress);
    }

    /**
     * 上传文件
     *
     * @param file 文件
     * @param path 相对路径
     */
    public static String uploadFile(String path, MultipartFile file) {
        return ossUtils.uploadFile(path, file);
    }

    /**
     * 上传文件
     *
     * @param url  文件url
     * @param path 相对路径
     */
    public static String uploadFile(String path, String url) {
        return ossUtils.uploadFile(path, url);
    }

    /**
     * 更新文件
     *
     * @param inputStream 文件流
     * @param oldName     旧文件名
     */
    public static String updateFile(String bucket, InputStream inputStream, String oldName) {
        return ossUtils.updateFile(bucket, inputStream, oldName);
    }

    /**
     * 更新文件
     *
     * @param file    文件
     * @param oldName 旧文件名
     */
    public static String updateFile(String bucket, MultipartFile file, String oldName) {
        return ossUtils.updateFile(bucket, file, oldName);
    }

    /**
     * 更新文件
     *
     * @param fileUrl 新文件路径
     * @param oldName 旧文件名
     */
    public static String updateFile(String bucket, String fileUrl, String oldName) {
        return ossUtils.updateFile(bucket, fileUrl, oldName);
    }

    /**
     * 删除文件
     */
    public static void delFile(String fileUrl) {
        if (StringUtils.isBlank(fileUrl)) {
            return;
        }

        fileUrl = getRelativeUrl(fileUrl);
        if (StringUtils.isBlank(fileUrl) || !fileUrl.contains("/")) {
            return;
        }

        String[] path = fileUrl.split("/");
        ossUtils.delFile(path[0], path[1]);
    }

    /**
     * 获取文件绝对路径
     */
    public static String getAbsoluteUrl(String fileName) {
        return ossUtils.getAbsoluteUrl(fileName);
    }

    /**
     * 获取文件相对路径
     */
    public static String getRelativeUrl(String url) {
        return ossUtils.getRelativeUrl(url);
    }

    /**
     * 根据相对路径获取绝对路径map
     */
    public static Map<String, String> getAbsoluteUrlMap(List<String> filePathList) {
        Map<String, String> map = new HashMap<>();
        if (CollectionUtil.isEmpty(filePathList)) {
            return map;
        }

        filePathList.forEach(filePath -> map.put(filePath, getAbsoluteUrl(filePath)));
        return map;
    }

    /**
     * 根据绝对路径获取相对路径map
     */
    public static Map<String, String> getRelativeMap(List<String> filePathList) {
        Map<String, String> map = new HashMap<>();
        if (CollectionUtil.isEmpty(filePathList)) {
            return map;
        }

        filePathList.forEach(filePath -> map.put(filePath, getRelativeUrl(filePath)));
        return map;
    }

    /**
     * 获取base64图片
     */
    public static String getBase64Img(String fileName) {
        String imgUrl = getAbsoluteUrl(fileName);
        try (InputStream inputStream = new URL(imgUrl).openStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int ch;
            while ((ch = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, ch);
            }

            return Base64.getEncoder().encodeToString(outputStream.toByteArray());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 检查图片
     */
    public static void checkImg(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            throw new SysException("请上传图片");
        }
        String[] suffixList = {"bmp", "jpg", "jpeg", "gif", "png"};
        if (Arrays.stream(suffixList).noneMatch(fileName::endsWith)) {
            throw new SysException("请上传图片");
        }
    }

    /**
     * 获取文件大小
     * @param fileName 文件名称
     */
    public static String getFileSize(String fileName) {
        Long bytes = ossUtils.getFileSize(fileName);

        BigDecimal rate = new BigDecimal(1024);
        RoundingMode roundingMode = RoundingMode.HALF_UP;

        BigDecimal kb = bytes == null ? BigDecimal.ZERO : new BigDecimal(bytes)
                .divide(rate, 2, roundingMode);

        return BigDecimal.ZERO.compareTo(kb) == 0 ? "0" : kb.compareTo(rate) < 0 ? kb + "KB"
                : kb.divide(rate, 2, roundingMode) + "MB";
    }
}
